package org.ainlolcat.ainscience;

import org.ainlolcat.ainscience.entity.Entity;
import org.ainlolcat.ainscience.entity.UnsupportedEntityTypeException;
import org.ainlolcat.ainscience.metaentity.MetaEntity;
import org.ainlolcat.ainscience.metaentity.UnsupportedMetaEntityTypeException;
import org.ainlolcat.ainscience.project.CircleException;
import org.ainlolcat.ainscience.project.Project;
import org.ainlolcat.ainscience.project.ProjectFileHandler;
import org.ainlolcat.ainscience.templates.Template;
import org.ainlolcat.ainscience.templates.TemplateFactory;
import org.ainlolcat.ainscience.utils.PathUtils;
import org.apache.log4j.Logger;
import org.jdom.JDOMException;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: ain
 * Date: 10/30/11
 * Time: 1:38 AM
 * manage all connection to data.
 */
public class Controller {
    private static Logger log = Logger.getLogger(Controller.class);

    private static Controller controller;
    private Project project;
    private List<UpdateListener> listeners;
    private List<Template> oobTemplates;


    public static Controller getInstance(){
        if (controller==null){
            controller = new Controller();
        }
        return controller;
    }

    private Controller(){
        listeners = new ArrayList<UpdateListener>();
        oobTemplates = new ArrayList<Template>();
        loadOOBTemplates();
    }

    public void loadOOBTemplates() {
        File dir = new File(PathUtils.getOOBTemplatesPath());
        String[] files = dir.list(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".xml");
            }
        });
        if (files == null)
            return;
        for (String file:files){
            try {
                loadOOBTemplate(PathUtils.getOOBTemplatesPath() + "/" + file);
            } catch (Exception e) {
                log.error(e);
            }
        }
    }

    public void loadOOBTemplate(String filename) throws JDOMException, IOException {
        Template template = TemplateFactory.parse(filename);
        oobTemplates.add(template);
    }

    /**
     * loadTemplates project from file. All links in file must be resolved
     * @param filename
     * @throws JDOMException
     * @throws IOException
     */
    public void loadProject(String filename) throws JDOMException, IOException {
        File file = new File(filename);
        project = new Project(file.getParentFile().getCanonicalPath());
        for (Template template: oobTemplates){
            project.addExternalTemplate(template);
        }
        project = new ProjectFileHandler().loadTemplates(filename, project);
        throwUpdateEvent();
        //MainWindow.getInstance().updateContent();
    }

    /**
     * save project with links to file
     * @param filename
     * @throws IOException
     * @throws CircleException
     */
    public void saveProject(String filename) throws IOException, CircleException, UnsupportedEntityTypeException, UnsupportedMetaEntityTypeException {
        new ProjectFileHandler().save(filename,project,true);
    }

    /**
     * project getter. No setter - only loadTemplates for now
     * @return
     */
    public Project getProject(){
        return project;
    }

    /**
     * loadTemplates template definition from file
     * @param filename
     * @throws JDOMException
     * @throws IOException
     */
    public void addTemplate(String filename) throws JDOMException, IOException {
        Template templ = TemplateFactory.parse(filename);
        project.addTemplate(templ);
    }

    /**
     * add Entru to list
     * @param entity
     */
    public void addEntity(Entity entity){
        project.addEntity(entity);
        throwUpdateEvent(entity, UpdateListener.CREATE_ENTITY_ACTION);
        //MainWindow.getInstance().updateEntriesList();
    }

    public void removeEntity(Entity ent){
        project.removeEntity(ent);
        throwUpdateEvent();
    }
    
    /**
     * add Entru to list
     * @param entity
     */
    public void addMetaEntity(MetaEntity entity){
        project.addMetaEntity(entity);
    }

    //listener's methods
    public void addUpdateListener(UpdateListener updl){
        if (!listeners.contains(updl)){
            listeners.add(updl);
        }
    }

    public void removeUpdateListener(UpdateListener updl){
        if (!listeners.contains(updl)){
            listeners.remove(updl);
        }
    }

    public void throwUpdateEvent(){
        for(int i=0;i<listeners.size();i++){
            UpdateListener listener = listeners.get(i);
            listener.onProjectUpdate();
        }
    }

    public void throwUpdateEvent(Entity entity, int action){
        for(int i=0;i<listeners.size();i++){
            UpdateListener listener = listeners.get(i);
            listener.onEntityUpdate(entity, action);
        }
    }
}
